﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web.UI;
using System.Xml.Linq;


namespace FlexySys.Common.Items
{
    public class DocumentRender : IDocumentRender
    {
        public XElement Template { get; set; }
        public IDocumentData Data { get; set; }

        private IControlFactory _ControlFactory;

        private Dictionary<string, WeakReference<ICommonControl>> _controls =
            new Dictionary<string, WeakReference<ICommonControl>>();


        public IControlFactory Factory
        {
            get
            {
                return _ControlFactory;
            }
            set
            {
                _ControlFactory = value;
            }
        }
        public System.Web.UI.Page Page { get; set; }
        public Action<System.Web.UI.Control> AddControl { get; set; }

        public Action<object, CommonCommandEventArgs> CommonCommandFunc { get; set; }

        public void Render()
        {
            var controls = Template
                            .Element("Controls")
                            .Elements("Control");

            foreach (var xElement in controls)
            {
                Control control = CreateControls(xElement);
                AddControl(control);
            }

        }

        private Control CreateControls(XElement Element)
        {

            string elType = Element.Attribute("Type").Value;
            Control control = (Control)Factory.CreateControl(elType);





            if (control is ICommonCommand && CommonCommandFunc != null)
            {
                ((ICommonCommand)control).ExecuteCommand += new CommonCommandEventHandler(CommonCommandFunc);
            }

            if (control is ICommonCommandSubscriber)
            {
                CommonCommandFunc = ((ICommonCommandSubscriber)control).OnCommand;
            }

            IEnumerable<string> collecton = Factory.ControlPropeties(control.GetType());
            if (collecton != null)
                foreach (string property in collecton)
                {
                    var att = Element.Attribute(property);
                    if (att != null)
                    {
                        object value;
                        PropertyInfo prop = control.GetType().GetProperty(property);
                        var converterAtt = prop.PropertyType.GetCustomAttribute<TypeConverterAttribute>();
                        if (converterAtt != null)
                        {
                            TypeConverter converter = (TypeConverter)Activator.CreateInstance(Type.GetType(converterAtt.ConverterTypeName));
                            value = converter.ConvertFrom(att.Value);
                        }
                        else
                        {
                            if (prop.PropertyType.BaseType != null && prop.PropertyType.BaseType.Equals(typeof(Enum)))
                                value = Convert.ChangeType(Enum.Parse(prop.PropertyType, att.Value, true), prop.PropertyType);
                            else
                                value = Convert.ChangeType((object)att.Value, prop.PropertyType);
                        }

                        prop.SetValue(control, value);
                    }
                }


            if (control is ICommonControl)
            {
                ICommonControl ctrl = ((ICommonControl)control);
                if (ctrl.ID != null)
                {
                    _controls.Add(ctrl.ID, new WeakReference<ICommonControl>(ctrl));
                    ctrl.DataItem =Data[ctrl.ID];
                }


            }

            if (control is IAddChild)
            {
                var Elements = Element.Elements("Control");
                foreach (var xElement in Elements)
                {
                    Control sub = CreateControls(xElement);
                    ((IAddChild)control).Add(sub);
                }
            }
            return control;

        }




        public XElement GetDataSource()
        {
            XElement data = new XElement("Data");



            foreach (var key in _controls)
            {
                ICommonControl ctrl;
                if (key.Value.TryGetTarget(out ctrl))
                {


                    IDataItem item = ctrl.DataItem;

                    XElement el = new XElement("Item", new XAttribute("ID", item.ID), new XElement("Value", item.Value));
                    data.Add(el);

                }

            }
            XElement doc = new XElement(new XElement("Document",
                            data));
            return doc;
        }
    }
}
